package ren.colorful.learnJava.nio;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class Reactor implements Runnable{
	
	public int id = 100001;
	public int bufferSize = 2048;

	@Override
	public void run() {
		init();
	}

	public void init() {
		try {
			//创建通道和选择器
			ServerSocketChannel socketChannel = ServerSocketChannel.open();
			Selector selector = Selector.open();
			InetSocketAddress inetSocketAddress = new InetSocketAddress(InetAddress.getLocalHost(),4700);
			socketChannel.socket().bind(inetSocketAddress);
			//设置通道非阻塞,绑定选择器
			socketChannel.configureBlocking(false);
			socketChannel.register(selector, SelectionKey.OP_ACCEPT).attach(id ++ );
			System.out.println("Servcer started ... port : 4700");
			listener(selector);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	public void listener(Selector selector) {
		try {
			while(true){
				Thread.sleep(1000);
				selector.select();//阻塞,直到有就绪事件为止
				Set<SelectionKey> readySelectionKey = selector.selectedKeys();
				Iterator<SelectionKey> iterator = readySelectionKey.iterator();
				while(iterator.hasNext()){
					SelectionKey selectionKey = iterator.next();
					//判断是哪个事件
					if(selectionKey.isAcceptable()){//客户端请求连接
						System.out.println(selectionKey.attachment() + " - 接受请求事件");
						//获取通道 接受连接
						//设置非阻塞模式(必须),同时需要注册 读写数据的事件,这样有消息触发的时候才能捕获
						ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
						serverSocketChannel
							.accept()
							.configureBlocking(false)
							.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE)
							.attach( id ++);
						System.out.println(selectionKey.attachment() + " - 已连接");
					}
					
					if(selectionKey.isReadable()){//读数据
						System.out.println(selectionKey.attachment() + " - 写数据事件");
						SocketChannel clientChannel = (SocketChannel) selectionKey.channel();
						ByteBuffer receiveBuf = ByteBuffer.allocate(bufferSize);
						clientChannel.read(receiveBuf);
						System.out.println(selectionKey.attachment() + " - 读取数据:" + getString(receiveBuf));
					}
					
					if(selectionKey.isWritable()){//写数据
						System.out.println(selectionKey.attachment() + " - 写数据事件");
						SocketChannel clientChannel = (SocketChannel) selectionKey.channel();
						ByteBuffer sendBuffer = ByteBuffer.allocate(bufferSize);
						String sendText = "hello\n";
						sendBuffer.put(sendText.getBytes());
						sendBuffer.flip();//写完数据后调用此方法
						clientChannel.write(sendBuffer);
					}
					
					if(selectionKey.isConnectable()){//连接
						System.out.println(selectionKey.attachment() + " - 连接事件");
					}
					iterator.remove();
				}
			}
		} catch (Exception e) {
			System.out.println("Error - " + e.getMessage());
			e.printStackTrace();
		}
	}

	public Object getString(ByteBuffer buffer) {
		String string = "";
		try {
			for (int i = 0; i < buffer.position(); i++) {
				string += (char)buffer.get(i);
			}
			return string;
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
	}

	
}
